package com.validated.validator;

import com.validated.constraint.ConstraintRegister;
import com.validated.constraint.ConstraintValidator;
import com.validated.util.ObjectUtil;
import org.springframework.core.annotation.AnnotationUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 验证器
 *
 * @author Moo
 * @date 2023/05/11
 */
public class ParameterValidatorImpl implements ParameterValidator {

    @Override
    public void entityValid(Object entity) {
        Field[] fields = entity.getClass().getDeclaredFields();
        if (ObjectUtil.isEmpty(fields)) {
            return;
        }

        for (Field field : fields) {
            field.setAccessible(true);
            Class<?> fieldClassType = field.getType();
            List<Annotation> validAnnotation = getValidAnnotation(field.getDeclaredAnnotations());
            if (ObjectUtil.isNotEmpty(validAnnotation)) {
                for (Annotation annotation : validAnnotation) {
                    validated(entity, fieldClassType, annotation, field);
                }
            }
        }
    }

    private List<Annotation> getValidAnnotation(Annotation[] annotations) {
        if (ObjectUtil.isNotEmpty(annotations)) {
            return Arrays.stream(annotations)
                    .filter(annotation -> isValidAnnotation(annotation))
                    .collect(Collectors.toList());
        }
        return null;
    }

    private boolean isValidAnnotation(Annotation annotation) {
        return annotation != null && ConstraintRegister.isRegistered(annotation.annotationType());
    }

    private void validated(Object entity, Class<?> valueType, Annotation annotation, Field field) {

        Map<String, Object> annotationAttributes = AnnotationUtils.getAnnotationAttributes(annotation);

        ConstraintValidator constraintValidator = ConstraintRegister.getConstraint(annotation.annotationType());

        if (constraintValidator != null) {
            validatedConstrain(constraintValidator, annotationAttributes, annotation, entity, valueType, field);
        }
    }


    private void validatedConstrain(ConstraintValidator constraintValidator, Map<String, Object> annotationAttributes, Annotation annotation,
                                    Object entity, Class valueType, Field field) {

        if (constraintValidator != null) {
            Object value = entity;
            String fieldName = "";
            if (field != null) {
                value = getFieldValue(field, entity);
                fieldName = field.getName();
            }
            boolean isValid = constraintValidator.isValid(annotation, value, valueType);
            if (!isValid) {
                throw new IllegalArgumentException(String.format("[%s]%s" ,fieldName, (String) annotationAttributes.get("msg")));
            }
        }
    }

    public static Object getFieldValue(Field field, Object object) {
        if (field != null && !Modifier.isStatic(field.getModifiers())) {
            field.setAccessible(true);
            try {
                return field.get(object);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
